<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>

  <body>
    <div id="app">
      x: {{ x }} <br />
      y: {{ y }}
    </div>
    <script type="module">
      import {
        createApp,
        reactive,
        onMounted,
        onUnmounted,
        toRefs
      } from "./node_modules/vue/dist/vue.esm-browser.js";

      // 封装鼠标移动坐标的函数
      // 在函数中注册了 onMounted 和 onUnmounted 事件
      // 当 vue 的生命周期 mounted 和 unmounted 被触发
      // 就会调用这两个事件
      function useMousePosition() {
        const position = reactive({
          x: 0,
          y: 0,
        });

        const update = (e) => {
          position.x = e.pageX;
          position.y = e.pageY;
        };

        // onMounted 是一个函数，有一个传入的参数也是一个函数
        // 意思是当 mounted 生命周期触发的时候，就会调用传入的函数参数
        onMounted(() => {
          window.addEventListener("mousemove", update);
        });

        onUnmounted(() => {
          window.removeEventListener("mousemove", update);
        });
        return toRefs(position);
      }

      const app = createApp({
        setup() {
          // 第一个参数 props
          // 第二个参数 context: Object
          //          attrs、emit、slots
          // setup 返回对象，可以在模板，methods ，computed 以及生命周期的钩子函数中
          // setup 的执行时机：在 props 被解析完毕，但是在组件实例创建之前执行的;
          // 所以在 setup 的内部，不能通过 this 去获取组件的实例，因为组件实例还没创建;
          // 所以 setup 是无法访问 data、computed、methods,此时的 this 指向 undefined
          // 通过使用 reactive 把普通对象转换成响应式对象
          const position = useMousePosition() 
          return {
            position,
          };
        }
      });
      console.log(app);

      app.mount("#app");
    </script>
  </body>
</html>
